using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;

using ClickToCall.ClickToCallToolbar.Builders;
using ClickToCall.IEEmbeddedObjectsLib;
using CommunicatorAPI;
using SHDocVw;
using mshtml;

namespace ClickToCall.ClickToCallToolbar
{
    /// <summary>
	/// This class inherits IEEmbeddedObject class from IEEmbeddedObjectsLib library and extends it. 
    /// ClickToCallToolbar is the one button bar and is shown in the Internet Explorer toolbar area
	/// </summary>
    [Guid("AE07101B-46D4-4a98-AF68-0333EA26E113")]
    [EmbeddedObjectAttribute("Communicator Click To Call", EmbeddedObjectStyle.Horizontal | EmbeddedObjectStyle.ExplorerToolbar, HelpText = "Shows bar that invokes Office Comunicator 2007 by clicking on SipURIs on a page.")]
    public partial class ClickToCallToolbar : ExplorerBarForm
    {
        #region static declarations
        private static Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
        private static Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E");
        protected static ContactCollection _contactCollection = new ContactCollection();
        #endregion
        #region const declarations
        const int E_ACCESSDENIED = unchecked((int)0x80070005L);
        const string OCTAG = "<a style='color:#676e74;text-decoration: underline' href='oc:id?{0}&n={1}'>{2}</a>";
        const string MailToTag = "mailto:{0}";
        const string phoneNumRegexPattern = @"((\(\d{3}\)?)|(\d{3}))?([\s-./]?)(\d{3})([\s-./]?)(\d{4})";
        #endregion
        #region private declarations
        private Regex _regExp = new Regex(phoneNumRegexPattern, RegexOptions.IgnoreCase);
        private Type[] SupportedElementTypes = new Type[] { 
            typeof(HTMLAnchorElementClass),
            typeof(HTMLHeaderElement),
            typeof(HTMLTableCellClass),
            typeof(HTMLTableClass),
            typeof(HTMLTableRowClass),
            typeof(HTMLTableColClass),
            typeof(HTMLDivElementClass),
            typeof(HTMLSpanElementClass),
            typeof(HTMLLIElementClass),
            typeof(HTMLParaElementClass),
            typeof(HTMLPhraseElementClass),
            typeof(HTMLTextElementClass)
        };
        private Dictionary<string, Contact> _contactsFound = new Dictionary<string, Contact>();
        private CommunicatorContactFilter _communicatorContactFilter;
        private OutlookContactFilter _outlookContactFilter;
        private Settings _settings;
        #endregion

        public ClickToCallToolbar()
        {
            Log.AddToLog("Initializing Toolbar", "");
            InitializeComponent();
            _settings = new RegistrySettingsProvider().Load();
            if (ExplorerBarForm.POWER)
                btnShowProperties.Image = this.IconOn;
            ExplorerAttached += new EventHandler(ClickToCallToolbar_ExplorerAttached);
        }
        #region startup methods
        private void Power(bool isOn)
        {
            BuildFilters();
            Log.AddToLog("Toolbar Power", isOn.ToString());
            ExplorerBarForm.POWER = isOn;
            if (isOn)
            {
                btnShowProperties.Image = this.IconOn;
                if (_contactCollection.Count == 0)
                {
                    ContactSearch();
                }
                ParseDocument(Explorer);
            }
            else
            {
                btnShowProperties.Image = this.IconOff;
                _contactsFound.Clear();
                Explorer.Refresh();
            }
        }

        private void BuildFilters()
        {
            _communicatorContactFilter = new CommunicatorContactFilter
                (
                    _settings.UseOCHome,
                    _settings.UseOCMobile,
                    _settings.UseOCWork,
                    false
                );

            _outlookContactFilter = new OutlookContactFilter
                (
                    _settings.UseOlkHome,
                    _settings.UseOlkMobile,
                    _settings.UseOlkWork,
                    _settings.UseOlkWork2,
                    false, false, false,
                    _settings.UseOlkCompany,
                    _settings.UseOlkPrimary
                );
        }

        private void ContactSearch()
        {
            Log.AddToLog("Starting Contact Search", "");

            this.Cursor = Cursors.WaitCursor;
            Explorer.StatusText = "Building Contact List...";
            _contactCollection.Clear();
            //start building a list of contacts from Office Communicator
            //and from Outlook.  If apps are not installed, the resulting
            //collection will be empty
            ContactBuilder cb;

            try
            {
                if (_settings.SearchOutlook)
                {
                    cb = new OutlookContactBuilder(_outlookContactFilter);
                    _contactCollection.AddRange(cb.GetContacts());
                    _contactCollection.Save();
                    Log.AddToLog("Outlook Contact Search", "Search Successful");
                }
            }
            catch (ContactBuilderException e)
            {
                Log.AddToLog("Error Creating Outlook Contact List", e.Message + ":" + e.InnerException.Message);
                //_isOutlookInstalled = false;
            }
            catch (System.IO.FileNotFoundException e)
            {
                Log.AddToLog("Error Creating Outlook Contact List", e.Message + ":" + e.InnerException.Message);
                //_isOutlookInstalled = false;
            }
            catch { }

            try
            {
                if (_settings.SearchOC)
                {
                    cb = new CommunicatorContactBuilder(_communicatorContactFilter);
                    _contactCollection.AddRange(cb.GetContacts());
                    _contactCollection.Save();
                    Log.AddToLog("Communicator Contact Search", "Search Successful");
                }
            }
            catch (ContactBuilderException e)
            {
                Log.AddToLog("Error Creating Communicator Contact List", e.Message + ":" + e.InnerException.Message);
                //_isCommunicatorInstalled = false;
            }
            catch (System.IO.FileNotFoundException e)
            {
                Log.AddToLog("Error Creating Communicator Contact List", e.Message + ":" + e.InnerException.Message);
                //_isCommunicatorInstalled = false;
            }
            catch { }
            
            this.Cursor = Cursors.Default;
            Explorer.StatusText = "Contact List Created. " + _contactCollection.Count + " Contacts Found.";
        }

        private void AsyncContactSearch()
        {
            _contactCollection.Clear();
            //start building a list of contacts from Office Communicator
            //and from Outlook.  If apps are not installed, the resulting
            //collection will be empty
            ContactBuilder cb;
            try
            {
                if (_settings.SearchOC)
                {
                    cb = new CommunicatorContactBuilder(_communicatorContactFilter);
                    cb.BeginGetContacts(new AsyncCallback(ContactSearchCallback), cb);
                }
            }
            catch (ContactBuilderException)
            {
                //_isCommunicatorInstalled = false;
            }

            try
            {
                if (_settings.SearchOutlook)
                {
                    cb = new OutlookContactBuilder(_outlookContactFilter);
                    cb.BeginGetContacts(new AsyncCallback(ContactSearchCallback), cb);
                }
            }
            catch (ContactBuilderException)
            {
                //_isOutlookInstalled = false;
            }
        }

        private void ContactSearchCallback(IAsyncResult aResult)
        {
            ContactBuilder cb = null;
            ContactCollection cc = null;
            try
            {
                cb = aResult.AsyncState as ContactBuilder;
                cc = cb.EndGetContacts(aResult);

                _contactCollection.AddRange(cc);
                _contactCollection.Save();
            }
            catch(Exception e)
            {
                MessageBox.Show(e.InnerException.Message);
            }
        }
        #endregion

        #region HTML Parsing
        private bool CheckSupport(IHTMLElement element)
        {
            for (int i = 0; i < SupportedElementTypes.Length; i++)
            {
                if (element.GetType() == SupportedElementTypes[i])
                    return true;
            }

            return false;
        }

        private bool ContainsValidChildren(IHTMLElement element)
        {
            IHTMLElementCollection elements = (IHTMLElementCollection)element.all;
            foreach (IHTMLElement ele in elements)
            {
                if (CheckSupport(ele)) return true;
            }
            return false;
        }

        private void ParseElement(IHTMLElement element)
        {
            IHTMLElementCollection elements = (IHTMLElementCollection)element.all;
            foreach (IHTMLElement ele in elements)
            {
                if (!CheckSupport(ele)) continue;
                if (ele.innerHTML != null && ele.innerText != null)
                {
                    //If element has child containers, wait till those elements
                    //are reached to perform F&R.
                    if (ContainsValidChildren(ele)) continue;
                    try
                    {
                        ele.innerHTML = FindAndReplace(ele.innerHTML);
                    }
                    catch (Exception e)
                    {
                        Log.AddToLog("Find And Replace Failure", e.Message);
                    }
                }
            }
        }

        private bool HasPhoneNumbers(string text)
        {
            if (text.Length <= 0) return false;
            MatchCollection mcol = this._regExp.Matches(text);
            if (mcol.Count > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        private bool HasContactName(string text)
        {
            if (text.Length <= 0) return false;

            foreach (Contact c in _contactCollection)
            {
                if (text.Contains(c.Fullname))
                {
                    return true;
                }
            }
            return false;
        }

        private void ParseDocument(IWebBrowser browser)
        {
            Log.AddToLog("Parsing Document", "Document Parsed from: " + browser.LocationURL);
            try
            {
                HTMLDocumentClass doc = (HTMLDocumentClass)browser.Document;
                if (doc == null || doc.body == null || doc.body.all == null || doc.body.innerHTML == null) return;

                //check for frames, if they exist parse each frame.
                FramesCollection frames = doc.frames;
                if (frames.length > 1)
                {
                    for (int i = 0; i < frames.length; i++)
                    {
                        object refIndex = i;
                        try
                        {
                            IHTMLWindow2 frame = (IHTMLWindow2)frames.item(ref refIndex);
                            //Use GetHTMLDocument here to avoid possible cross site scripting permission errors
                            IHTMLDocument2 doc2 = GetHTMLDocument(frame);
                            if (doc2 == null) continue;
                            IHTMLElement element = (IHTMLElement)doc2.body;
                            if (HasContactName(element.innerHTML) || HasPhoneNumbers(element.innerHTML))
                            {
                                ParseElement(element);
                            }
                        }
                        catch (Exception)
                        {
                            continue;
                        }
                    }
                }
                else
                {
                    IHTMLElement element = (IHTMLElement)doc.body;
                    if (HasContactName(element.innerHTML) || HasPhoneNumbers(element.innerHTML))
                    {
                        ParseElement(element);
                    }
                }
            }
            catch(Exception e)
            {
                Log.AddToLog("Parsing Document", "Parsing Failed from: " + browser.LocationURL + " " + e.Message);
            }
        }

        private string FindAndReplace(string bodyHTML)
        {
            if (bodyHTML.Length <= 0) return bodyHTML;
            MatchCollection matches = this._regExp.Matches(bodyHTML);
            if(matches.Count > 0)
                Log.AddToLog("Performing Find And Replace", "Matches = " + matches.Count);
            foreach (Match match in matches)
            {
                if (_contactCollection.Count > 0)
                {
                    bool isFound = false;
                    foreach (Contact contact in _contactCollection)
                    {
                        string id = null;
                        try
                        {
                            #region Compare each match against Phones collection in Contact
                            if (StripPhoneNumber(contact.Phones.Business2TelephoneNumber).Equals(StripPhoneNumber(match.Value)))
                            {
                                if (id == null)
                                    id = Guid.NewGuid().ToString();
                                bodyHTML = bodyHTML.Replace(match.Value, string.Format(OCTAG, id, StripPhoneNumber(match.Value), match.Value));
                                isFound = true;
                            }
                            else if (StripPhoneNumber(contact.Phones.BusinessTelephoneNumber).Equals(StripPhoneNumber(match.Value)))
                            {
                                if (id == null)
                                    id = Guid.NewGuid().ToString();
                                bodyHTML = bodyHTML.Replace(match.Value, string.Format(OCTAG, id, StripPhoneNumber(match.Value), match.Value));
                                isFound = true;
                            }
                            else if (StripPhoneNumber(contact.Phones.CallbackTelephoneNumber).Equals(StripPhoneNumber(match.Value)))
                            {
                                if (id == null)
                                    id = Guid.NewGuid().ToString();
                                bodyHTML = bodyHTML.Replace(match.Value, string.Format(OCTAG, id, StripPhoneNumber(match.Value), match.Value));
                                isFound = true;
                            }
                            else if (StripPhoneNumber(contact.Phones.CarTelephoneNumber).Equals(StripPhoneNumber(match.Value)))
                            {
                                if (id == null)
                                    id = Guid.NewGuid().ToString();
                                bodyHTML = bodyHTML.Replace(match.Value, string.Format(OCTAG, id, StripPhoneNumber(match.Value), match.Value));
                                isFound = true;
                            }
                            else if (StripPhoneNumber(contact.Phones.CompanyMainTelephoneNumber).Equals(StripPhoneNumber(match.Value)))
                            {
                                if (id == null)
                                    id = Guid.NewGuid().ToString();
                                bodyHTML = bodyHTML.Replace(match.Value, string.Format(OCTAG, id, StripPhoneNumber(match.Value), match.Value));
                                isFound = true;
                            }
                            else if (StripPhoneNumber(contact.Phones.HomeTelephoneNumber).Equals(StripPhoneNumber(match.Value)))
                            {
                                if (id == null)
                                    id = Guid.NewGuid().ToString();
                                bodyHTML = bodyHTML.Replace(match.Value, string.Format(OCTAG, id, StripPhoneNumber(match.Value), match.Value));
                                isFound = true;
                            }
                            else if (StripPhoneNumber(contact.Phones.MobileTelephoneNumber).Equals(StripPhoneNumber(match.Value)))
                            {
                                if (id == null)
                                    id = Guid.NewGuid().ToString();
                                bodyHTML = bodyHTML.Replace(match.Value, string.Format(OCTAG, id, StripPhoneNumber(match.Value), match.Value));
                                isFound = true;
                            }
                            else if (StripPhoneNumber(contact.Phones.OtherTelephoneNumber).Equals(StripPhoneNumber(match.Value)))
                            {
                                if (id == null)
                                    id = Guid.NewGuid().ToString();
                                bodyHTML = bodyHTML.Replace(match.Value, string.Format(OCTAG, id, StripPhoneNumber(match.Value), match.Value));
                                isFound = true;
                            }
                            else if (StripPhoneNumber(contact.Phones.PrimaryTelephoneNumber).Equals(StripPhoneNumber(match.Value)))
                            {
                                if (id == null)
                                    id = Guid.NewGuid().ToString();
                                bodyHTML = bodyHTML.Replace(match.Value, string.Format(OCTAG, id, StripPhoneNumber(match.Value), match.Value));
                                isFound = true;
                            }
                            else
                            {
                                isFound = false;
                            }
                        #endregion

                            if (contact.Fullname.Length > 0)
                            {
                                if (bodyHTML.IndexOf(contact.Fullname, StringComparison.OrdinalIgnoreCase) >= 0)
                                {
                                    if (id == null)
                                        id = Guid.NewGuid().ToString();
                                    bodyHTML = Replace(bodyHTML, contact.Fullname, string.Format(OCTAG, id, CheckContactForPhone(contact), contact.Fullname), StringComparison.OrdinalIgnoreCase);
                                    if (!isFound) _contactsFound.Add(id, contact);
                                }
                            }

                            if (isFound)
                            {
                                _contactsFound.Add(id, contact);
                                break;
                            }
                        }
                        catch (Exception e)
                        {
                            Log.AddToLog("Find And Replace Failed", "Contact: " + contact.Fullname + " " +e.Message);
                        }
                    }

                    if (!isFound)
                    {
                        bodyHTML = bodyHTML.Replace(match.Value, string.Format(OCTAG, "~", StripPhoneNumber(match.Value), match.Value));
                    }
                }
                else
                {
                    bodyHTML = bodyHTML.Replace(match.Value, string.Format(OCTAG, "~", StripPhoneNumber(match.Value), match.Value));
                }
            }

            if (matches.Count <= 0)
            {
                Log.AddToLog("Find And Replace Name", "");
                foreach (Contact contact in _contactCollection)
                {
                    try
                    {
                        if (contact.Fullname.Length > 0)
                        {
                            if (bodyHTML.IndexOf(contact.Fullname, StringComparison.OrdinalIgnoreCase) >= 0)
                            {
                                string id = Guid.NewGuid().ToString();
                                bodyHTML = Replace(bodyHTML, contact.Fullname, string.Format(OCTAG, id, CheckContactForPhone(contact), contact.Fullname), StringComparison.OrdinalIgnoreCase);
                                _contactsFound.Add(id, contact);
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Log.AddToLog("Find And Replace Failed", "Contact: " + contact.Fullname + " " + e.Message);
                    }
                }
            }

            return bodyHTML;
        }

        private string CheckContactForPhone(Contact contact)
        {
            string result = "*";
            if (contact.Phones.BusinessTelephoneNumber.Length > 0)
            {
                return StripPhoneNumber(contact.Phones.BusinessTelephoneNumber);
            }
            else if (contact.Phones.Business2TelephoneNumber.Length > 0)
            {
                return StripPhoneNumber(contact.Phones.Business2TelephoneNumber);
            }
            else if (contact.Phones.MobileTelephoneNumber.Length > 0)
            {
                return StripPhoneNumber(contact.Phones.MobileTelephoneNumber);
            }
            else if (contact.Phones.HomeTelephoneNumber.Length > 0)
            {
                return StripPhoneNumber(contact.Phones.HomeTelephoneNumber);
            }
            else if (contact.Phones.PrimaryTelephoneNumber.Length > 0)
            {
                return StripPhoneNumber(contact.Phones.PrimaryTelephoneNumber);
            }
            else if (contact.Phones.OtherTelephoneNumber.Length > 0)
            {
                return StripPhoneNumber(contact.Phones.OtherTelephoneNumber);
            }
            else
            {
                return result;
            }
        }
        
        private string StripPhoneNumber(string phoneNumber)
        {
            if (!string.IsNullOrEmpty(phoneNumber))
            {
                phoneNumber = phoneNumber.Replace("(", string.Empty);
                phoneNumber = phoneNumber.Replace(")", string.Empty);
                phoneNumber = phoneNumber.Replace("-", string.Empty);
                phoneNumber = phoneNumber.Replace(".", string.Empty);
                phoneNumber = phoneNumber.Replace(" ", string.Empty);
            }
            return phoneNumber;
        }

        public string Replace(string original, string oldValue, string newValue, StringComparison comparisionType)
        {
            string result = original;

            if (!string.IsNullOrEmpty(newValue))
            {
                int index = -1;
                int lastIndex = 0;

                System.Text.StringBuilder buffer = new System.Text.StringBuilder();

                while ((index = original.IndexOf(oldValue, index + 1, comparisionType)) >= 0)
                {
                    buffer.Append(original, lastIndex, index - lastIndex);
                    buffer.Append(newValue);

                    lastIndex = index + oldValue.Length;
                }
                buffer.Append(original, lastIndex, original.Length - lastIndex);

                result = buffer.ToString();
            }
            return result;
        }

        private bool ParseAndPerformCommand(string cmdLine)
        {
            //grab keys
            Keys curKeys = Control.ModifierKeys;

            bool result = false;
            if (string.IsNullOrEmpty(cmdLine))
                throw new ArgumentNullException("cmdLine");

            //Check if this is the ClickToCallToolbar command
            int indexCmdDelim = -1;
            indexCmdDelim = cmdLine.IndexOf('?');
            if (!cmdLine.Substring(0, 3).Equals("oc:") || indexCmdDelim == -1)
                return result;

            // Get ClickToCallToolbar command name
            string cmdName = cmdLine.Substring(3, indexCmdDelim - 3);
            string id = cmdLine.Substring(indexCmdDelim + 1, cmdLine.IndexOf('&')-6);
           
            string phone = string.Empty;
            if(!cmdLine.Contains("*"))
                phone = cmdLine.Split('&')[1].Substring(2, cmdLine.Split('&')[1].Length - 2);

            if (!string.IsNullOrEmpty(id))
            {
                result = true;
                try
                {
                    Contact contact = null;
                    if (_contactsFound.TryGetValue(id, out contact))
                    {
                        contact.MatchedNumber = phone;
                        
                        string mailto = string.Format(MailToTag, contact.Email);
                        object flag = null, target = null, post = null, header = null;

                        //Create Email
                        if (curKeys == Keys.Shift)
                        {
                            if (!string.IsNullOrEmpty(contact.Email))
                            {
                                Explorer.Navigate(mailto, ref flag, ref target, ref post, ref header);
                            }
                            else
                            {
                                MessageBox.Show("This contact does not have an email address.", "Unable to Create Email", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                        }
                        //Start VoIP Call
                        if (curKeys == Keys.Alt)
                        {
                            if (!string.IsNullOrEmpty(contact.Sip))
                            {
                                StartSipVoice(contact);
                            }
                            else
                            {
                                StartVoIPCall(contact);
                            }
                        }
                        //Start Conversation or VoIP
                        if (curKeys == Keys.None)
                        {
                            if (!string.IsNullOrEmpty(contact.Sip))
                            {
                                StartInstantMessage(contact);
                            }
                            else
                            {
                                if (!string.IsNullOrEmpty(contact.MatchedNumber))
                                {
                                    StartVoIPCall(contact);
                                }
                                else
                                {
                                    MessageBox.Show("This contact is not in your Communicator Contact List.", "Unable to Start Conversation", MessageBoxButtons.OK, MessageBoxIcon.Information);
                                }
                            }
                        }
                    }
                    else if (id.Equals("~"))//Just a generic number, not a contact
                    {
                        StartVoIPCall(phone);
                    }
                }
                catch (Exception e)
                {
                    Log.AddToLog("Perform Command Failure", e.Message);
                    MessageBox.Show("Unable to handle request.");
                }
            }
            return result;
        }

        public IHTMLDocument2 GetHTMLDocument(IHTMLWindow2 htmlWindow)
        {
            if (htmlWindow == null)
            {
                return null;
            }

            try
            {
                IHTMLDocument2 doc = htmlWindow.document;
                return doc;
            }
            catch (COMException comEx)
            {
                //Seems to occasionally get thrown as a COMException,
                //if it the error is ACCESSDENIED then continue to conversion.
                if (comEx.ErrorCode != E_ACCESSDENIED)
                {
                    return null;
                }
            }
            catch (System.UnauthorizedAccessException)
            {
            }
            catch
            {
                return null;
            }

            // Possible cross site frame, so try to coonvert
            try
            {
                //Interoped from COM Interface in IEEmbeddedObjectsLib
                ClickToCall.IEEmbeddedObjectsLib.IServiceProvider sp = (ClickToCall.IEEmbeddedObjectsLib.IServiceProvider)htmlWindow;

                Object brws = null;
                sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out brws);

                //create a new browser
                SHDocVw.IWebBrowser2 browser = (SHDocVw.IWebBrowser2)(brws);
                //grab the document from new browser;
                return (IHTMLDocument2)browser.Document;
            }
            catch
            {
            }

            return null;
        }
        #endregion

        #region Communicator Usage Methods
        private void StartInstantMessage(Contact c)
        {
            Messenger communicator;
            try
            {
                communicator = MessengerInstance.Instance.Messenger;
                IMessengerContact mc = (IMessengerContact)communicator.GetContact(c.Sip, null);
                communicator.InstantMessage(mc);
            }
            catch (MessengerInstanceException)
            {
                MessageBox.Show("Office Communicator must be running to complete this operation.");
            }
            catch
            {
                if (!string.IsNullOrEmpty(c.MatchedNumber))
                {
                    StartVoIPCall(c);
                    return;
                }
                MessageBox.Show("The selected contact does not have a valid Office Communicator ID.", 
                    "Unable to Start Instant Message", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            finally
            {
                communicator =null;
            }
        }

        private void StartSipVoice(Contact c)
        {
            Messenger communicator;
            try
            {
                communicator = MessengerInstance.Instance.Messenger;
                IMessengerContact mc = (IMessengerContact)communicator.GetContact(c.Sip, null);
                communicator.StartVoice(mc);
            }
            catch (MessengerInstanceException)
            {
                MessageBox.Show("Office Communicator must be running to complete this operation.");
            }
            catch
            {
                MessageBox.Show("The selected contact does not have a valid Office Communicator ID.", 
                    "Unable to Start Call", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            finally
            {
                communicator = null;
            }
        }

        private void StartVoIPCall(Contact c)
        {
            Messenger communicator;
            try
            {
                communicator = MessengerInstance.Instance.Messenger;
                string pn = StripPhoneNumber(c.MatchedNumber);
                communicator.Phone(pn, MPHONE_TYPE.MPHONE_TYPE_CUSTOM, pn);
            }
            catch (MessengerInstanceException)
            {
                MessageBox.Show("Office Communicator must be running to complete this operation.");
            }
            catch
            {
                MessageBox.Show("The selected contact cannot be called.",
                    "Unable to Start Call", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            finally
            {
                communicator = null;
            }
        }
        
        private void StartVoIPCall(string phone)
        {
            Messenger communicator;
            try
            {
                communicator = MessengerInstance.Instance.Messenger;
                communicator.Phone(phone, MPHONE_TYPE.MPHONE_TYPE_CUSTOM, phone);
            }
            catch (MessengerInstanceException)
            {
                MessageBox.Show("Office Communicator must be running to complete this operation.");
            }
            catch
            {
                MessageBox.Show("The selected number cannot be called.",
                    "Unable to Start Call", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            finally
            {
                communicator = null;
            }
        }
        #endregion
        
        #region Dispose

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (Log.Count > 0)
                    Log.Save();
                if (ExplorerBarForm.TABCOUNT == 1)
                    _contactCollection.Delete();
                if (Explorer != null)
                {
                    Explorer.DocumentComplete -= new DWebBrowserEvents2_DocumentCompleteEventHandler(Explorer_DocumentComplete);
                    Explorer.BeforeNavigate2 -= new DWebBrowserEvents2_BeforeNavigate2EventHandler(Explorer_BeforeNavigate2);
                    Explorer.NewWindow3 -= new DWebBrowserEvents2_NewWindow3EventHandler(Explorer_NewWindow3);
                    ExplorerAttached -= new EventHandler(ClickToCallToolbar_ExplorerAttached);
                }
                if (components != null)
                    components.Dispose();
            }
            base.Dispose(disposing);

        }

        #endregion

        #region Explorer events handlers

        void ClickToCallToolbar_ExplorerAttached(object sender, EventArgs e)
        {
            if (Explorer != null)
            {
                Explorer.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(Explorer_DocumentComplete);
                Explorer.BeforeNavigate2 += new DWebBrowserEvents2_BeforeNavigate2EventHandler(Explorer_BeforeNavigate2);
                Explorer.NewWindow3 += new DWebBrowserEvents2_NewWindow3EventHandler(Explorer_NewWindow3);
            }
        }


        void Explorer_DocumentComplete(object pDisp, ref object URL)
        {
            if (ExplorerBarForm.POWER)
            {
                if (Explorer.LocationURL.Equals(URL))
                {
                    IWebBrowser browse = (IWebBrowser)pDisp;
                    ParseDocument(browse);
                }
            }
        }

        void Explorer_BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
        {
            string strURL = URL.ToString();
            if (!string.IsNullOrEmpty(strURL))
            {
                if (ParseAndPerformCommand(strURL))
                {
                    Cancel = true;
                }
            }
        }

        void Explorer_NewWindow3(ref object ppDisp, ref bool Cancel, uint dwFlags, string bstrUrlContext, string bstrUrl)
        {
            string strURL = bstrUrl.ToString();
            if (!string.IsNullOrEmpty(strURL))
            {
                if (ParseAndPerformCommand(strURL))
                {
                    Cancel = true;
                }
            }
        }

        #endregion

        #region UI Events
        void btnShowProperties_Click(object sender, EventArgs e)
        {
            if(ExplorerBarForm.POWER)
                Power(false);
            else
                Power(true);
        }
        #endregion
    }

    [Guid("99DDDDD3-49FF-4fd2-9953-8B2660E010FC")]
    [ClassInterface(ClassInterfaceType.AutoDispatch)]
    public class MenuBar : IOleCommandTarget
    {

        FormSettings _formSettings = null;

        private bool CheckRegistry()
        {
            //Create menu item
            try
            {
                Microsoft.Win32.RegistryKey extKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\ClickToCall");
                bool b = Convert.ToBoolean(extKey.GetValue("Outlook"));
                return b;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// Override this method to handle MenuLinkClick event.
        /// </summary>
        /// <param name="ea"></param>
        protected virtual void OnMenuLinkClicked(EventArgs ea)
        {
            if (_formSettings == null)
            {
                _formSettings = new FormSettings(CheckRegistry(), true);
            }
            if (_formSettings != null)
            {
                try
                {
                    if (_formSettings.ShowDialog() == DialogResult.OK)
                    {
                        if (_formSettings.ChangeMade)
                        {
                            Application.DoEvents();
                        }
                    }
                }
                catch (Exception)
                {
                }
            }
        }

        #region IOleCommandTarget Members

        public int QueryStatus(ref Guid pguidCmdGroup, uint nCmds, IntPtr prgCmds, IntPtr pCmdTxt)
        {
            OLECMD[] ocmd = (
                            OLECMD[])Marshal.PtrToStructure(
                                prgCmds, typeof(OLECMD[])
                            );
            for (uint i = 0; i < nCmds; i++)
            {
                ocmd[i].cmdf =
                    (UInt64)OLECMDF.OLECMDF_ENABLED |
                    (UInt64)OLECMDF.OLECMDF_SUPPORTED;
                Marshal.StructureToPtr(
                    ocmd, prgCmds, false
                );
            }
            return 0;
        }

        public int Exec(ref Guid pguidCmdGroup, uint nCmdId, uint nCmdExecOpt, IntPtr pvaIn, IntPtr pVaOut)
        {
            if (nCmdId == 0 && nCmdExecOpt != (long)OLECMDEXECOPT.OLECMDEXECOPT_SHOWHELP)
            {
                OnMenuLinkClicked(EventArgs.Empty);
            }
            return 0;
        }

        #endregion
    }
}
